#include <iostream>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <stdlib.h>
#include "pipeline.h"
#include "process.h"


Pipeline::Pipeline()
{
    input = "";
    output = "";
}

Pipeline::~Pipeline()
{
    for (std::vector<Process *>::iterator i = processes.begin(); i != processes.end(); ++i)
    {
        delete *i;
    }
}

void Pipeline::addProcess(Process * proces)
{
    processes.push_back(proces);
}

void Pipeline::setInput(std::string file)
{
    input = file;
}

void Pipeline::setOutput(std::string file, bool append)
{
	output = file;
    this->append = append;
}

void Pipeline::execute() const
{
	int inFile = !input.empty() ? open(input.c_str(), O_RDONLY) : 0;
	int outFile = !output.empty() ? open(output.c_str(), O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC), 0644) : 1;
	int previous = inFile;

    for (unsigned int i=0; i<processes.size(); ++i)
    {
		int p[2];

		if (pipe(p) == -1)
		{
			std::cerr << "pipe failed\n";
		}

		if (i == processes.size() - 1)
		{
			//cout << "*1. closing " << p[1] << endl;
			close(p[1]);
			p[1] = outFile;
		}

		switch (fork())
		{
			case -1:
				std::cerr << "fork failed\n";
				return;
			break;
			case 0: // child
				close(p[0]);

				dup2(previous, 0);
				dup2(p[1], 1);

				if (previous > 2)
				{
					close(previous);
				}

				if (p[1] > 2)
				{
					close(p[1]);
				}

				(processes)[i]->execute();

				// end the child process
				exit(0);
			break;
			default: // parent
				if (previous > 2)
				{
					close(previous);
				}

				if (p[1] > 2)
				{
					close(p[1]);
				}
				previous = p[0];
			break;
		}
    }

    if (previous > 2)
    {
		close(previous);
	}

	int status;

	while (wait(&status) >= 0);
}
